package com.lagou.edu.factory;

import com.lagou.edu.anno.*;
import net.sf.cglib.core.CollectionUtils;
import org.reflections.Reflections;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 根据注解方式实例化Bean
 * @author shenguotao
 * @date 2021/02/10
 */
public class AnnotationBeanFactory {
    /**
     * 实例对象集合
     */
    private static Map<String,Object> objMap = new ConcurrentHashMap();
    /**
     * Class对象与BeanName的映射集合
     */
    private static Map<Class,String> classBeanNameMap = new ConcurrentHashMap<>();
    private static Reflections reflections = null;
    static {
        //配置扫描包
        reflections = new Reflections("com.lagou.edu");
        Set<Class> annoClass = new HashSet<>();
        annoClass.add(Componment.class);
        annoClass.add(Controller.class);
        annoClass.add(Servcie.class);
        annoClass.add(Responsity.class);
        try {

            //获取指定注解的类对象集合
            Set<Class> clazzSet = getTypesAnnotatedWith(annoClass);
            //实例化对象
            for(Class aClass : clazzSet){
                //实例化对象
                Object obj = aClass.newInstance();
                //获取类上的注解
                Annotation annotation = getAnnotation(annoClass,aClass);
                //获取注解属性值value,调用value()方法获取
                Method method = annotation.getClass().getMethod("value");
                String value = (String) method.invoke(annotation, null);
                if(null == value || "".equals(value.trim())) {
                    //如果没有设置beanName,取类名，且首字符小写
                    value = aClass.getSimpleName();
                    value = value.replace(String.valueOf(value.charAt(0)),String.valueOf(value.charAt(0)).toLowerCase(Locale.ENGLISH));
                }
                objMap.put(value,obj);
                classBeanNameMap.put(aClass,value);

            };
            //依赖注入
            dealDependencyInjection();

        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    /**
     * 依赖注入
     */
    public static void dealDependencyInjection() throws IllegalAccessException {
        //依赖关系维护
        for(Map.Entry<String,Object> entry : objMap.entrySet()) {
            Object obj = entry.getValue();
            Field[] fields = obj.getClass().getDeclaredFields();
            //遍历所有属性
            for(Field field :fields) {
                //暴力访问，访问私有属性
                field.setAccessible(true);
                //获取属性类型
                Class fieldType = field.getType();
                //判断属性上是否由Autowired注解，进行依赖注入
                if(field.isAnnotationPresent(Autowired.class) && field.getAnnotation(Autowired.class).required()){
                    //如果由Qualifer注解，采用byName方式的注入
                    Qualifier qualifier = field.getAnnotation(Qualifier.class);
                    if(qualifier != null) {
                        String value = qualifier.value();
                        Object fieldObj = objMap.get(value);
                        field.set(obj,fieldObj);
                    }else {
                        //否则以byType方式注入
                        String beanName = classBeanNameMap.get(fieldType);
                        Object fieldObj = null;
                        if(beanName == null || null == objMap.get(beanName)){
                            fieldObj = getSubTypeObj(fieldType,reflections);
                        }else {
                            fieldObj = objMap.get(beanName);
                        }
                        field.set(obj,fieldObj);

                    }

                }
            }

            //处理事务
            createAopTransactionProxy(entry.getKey(),obj);

        }
    }

    /**
     * 创建事务动态代理对象
     * @param obj
     */
    public static void createAopTransactionProxy(String key,Object obj) {
        //事务维护
        if(obj.getClass().isAnnotationPresent(Transactional.class)) {
            //获取动态代理工厂
            ProxyFactory proxyFactory = (ProxyFactory) objMap.get("proxyFactory");
            //如果实现了接口，采用JDK动态代理模式
            if(null != obj.getClass().getInterfaces() && obj.getClass().getInterfaces().length > 0) {
                obj = proxyFactory.getJdkProxyObject(obj);
            }else {
                //否则采用Cglib动态代理模式
                obj = proxyFactory.getCglibObject(obj);
            }
            objMap.put(key,obj);
        }
    }

    /**
     * 根据注解Class,获取指定注解的所有类
     * @param annotationClass
     * @return
     */
    public static Set<Class> getTypesAnnotatedWith(Set<Class> annotationClass) throws Exception{
        Set<Class> classSet = new HashSet<>();
        annotationClass.forEach(aClass -> {
            classSet.addAll(reflections.getTypesAnnotatedWith(aClass));
        });
        return classSet;
    }

    /**
     * 根据beanName获取对象
     * @param beanName
     * @return
     */
    public static Object getBean(String beanName) {
        return objMap.get(beanName);
    }

    /**
     * 根据注解字节码对象类上的注解对象
     * @param classSet
     * @return
     */
    public static Annotation getAnnotation(Set<Class> classSet,Class targetClass) {
        Annotation annotation = null;
        for(Class clazz : classSet) {
            annotation = targetClass.getAnnotation(clazz);
            if(annotation != null) {
                break;
            }
        }
        return annotation;
    }

    /**
     * 根据类型查询子类对象
     * @param targetClass
     * @return
     */
    public static Object getSubTypeObj(Class targetClass,Reflections reflections) {
        Object subBean = null;
        Set<Class> subTypes = reflections.getSubTypesOf(targetClass);
        for (Object subType : subTypes) {
            String subBeanName = classBeanNameMap.get(subType);
            subBean = objMap.get(subBeanName);
            if(null != subBean) {
                break;
            }
        }
        return subBean;
    }

}

